#include "PacketHandler.h"
#include "Server.h"
#include <memory.h>

using namespace car;

PacketHandler::PacketHandler(void)
{
}

PacketHandler::~PacketHandler(void)
{
}

 void PacketHandler::handlePacket( LASAddress & address, Server * server, unsigned char data[], int size )
{
	if( size >= kMinPacketLength )
	{
		unsigned int pos = 0;
		PlayerState playerState;

		memcpy( &playerState, &data[pos], sizeof( PlayerState ) );
		pos += sizeof( PlayerState );
		switch( playerState )
		{
		case PlayerStateLoggingIn:
			{
				printf("receive login request\n");
				unsigned char nameSize;
				memcpy( &nameSize, &data[pos], sizeof( unsigned char ) );
				pos += sizeof( unsigned char );
				char name[kMaxPlayerNameLength];
				memcpy( &name[0], &data[pos], ( unsigned int )nameSize );
				pos += nameSize;
				unsigned char passwordSize;
				memcpy( &passwordSize, &data[pos], sizeof( unsigned char ) );
				pos += sizeof( unsigned char );
				char password[kMaxPasswordLength];
				if( passwordSize > kMaxPasswordLength )
					break;
				memcpy( &password[0], &data[pos], ( unsigned int )passwordSize );
				pos += passwordSize;

				unsigned int playerId = server->generatePlayerId( name, ( unsigned int )nameSize, password, ( unsigned int )passwordSize );
				if( !server->hasPlayer( playerId ) )
				{
					Player * player = new Player( playerId );
					player->setPlayerName( &name[0], nameSize );
					player->setPlayerState( PlayerStateInHall );
					
					server->addPlayer( player );
					server->getPlayer( playerId )->setAddress( address );

					static unsigned short port = 30001;
					int count = 0;
					bool success = false;
					
					while( true )
					{
						if( player->startConnection( port ) )
						{							
							success = true;
							break;
						}
						port++;
						count++;
					}
				}
				break;
			}
		case PlayerStateLoggingOut:
			{
				printf("receive logout request\n");
				unsigned int playerId;
				memcpy( &playerId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				server->removePlayer( playerId );
				break;
			}
		case PlayerStateInHall:
			{
				printf("receive in hall packet\n");
				/*unsigned int playerId;
				memcpy( &playerId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Player * player = server->getPlayer( playerId );
				if( player )
				{
					if( player->getPlayerState() != PlayerStateInHall )
					{
						player->setPlayerState( PlayerStateInHall );
					}
				}*/
				break;
			}
		case PlayerStateCreatingRoom:
			{
				printf("receive create room request\n");
				unsigned int playerId;
				memcpy( &playerId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Player * player = server->getPlayer( playerId );
				if( !player || ( player && player->getPlayerState() != PlayerStateInHall ) )
					break;
				unsigned int mapId;
				memcpy( &mapId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				unsigned char numForces;
				memcpy( &numForces, &data[pos], sizeof( unsigned char ) );
				pos += sizeof( unsigned char );
				unsigned int roomId = server->generateRoomId();
				unsigned char maxCapacity = server->getMapList()->getMaxCapacityOfMap( mapId );
				Room * room = new Room( roomId, playerId, maxCapacity );
				room->setRoomState( RoomStateWaiting );
				room->setMapId( mapId );
				if( room->addPlayer( player ) )
					player->enterRoom( roomId );
				server->addRoom( room );
				break;
			}
		case PlayerStateEnteringRoom:
			{
				printf("receive entering request\n");
				unsigned int playerId;
				memcpy( &playerId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Player * player = server->getPlayer( playerId );
				if( !player || ( player && player->getPlayerState() != PlayerStateInHall ) )
					break;
				unsigned int roomId;
				memcpy( &roomId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Room * room = server->getRoom( roomId );
				if( room && room->addPlayer( player ) )
					player->enterRoom( roomId );
				break;
			}
		case PlayerStateInRoom:
			{
				printf("receive in room\n");
				/*unsigned int playerId;
				memcpy( &playerId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				unsigned int roomId;
				memcpy( &roomId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Player * player = server->getPlayer( playerId );
				if( player )
				{
					if( player->getPlayerState() != PlayerStateInRoom )
					{
						player->setPlayerState( PlayerStateInHall );
					}
				}*/
				break;
			}
		case PlayerStateLeavingRoom:
			{
				printf("receive leave room request\n");
				unsigned int playerId;
				memcpy( &playerId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Player * player = server->getPlayer( playerId );
				if( !player || ( player && player->getPlayerState() != PlayerStateInRoom ) )
					break;
				unsigned int roomId;
				memcpy( &roomId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Room * room = server->getRoom( roomId );
				if( room && room->removePlayer( playerId ) )
				{					
					player->leaveRoom();
					if( player->getPlayerId() == room->getHostId() )
						room->clearPlayerList();
					server->removeRoom( room->getRoomId() );
				}
				break;
			}
		case PlayerStateStartingGame:
			{
				printf("receive start game request\n");
				unsigned int playerId;
				memcpy( &playerId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Player * player = server->getPlayer( playerId );
				if( !player || ( player && player->getPlayerState() != PlayerStateInRoom ) )
					break;
				unsigned int roomId;
				memcpy( &roomId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Room * room = server->getRoom( roomId );
				if( !room || room->getHostId() != playerId || room->getCurrentPlayerNumber() == 1 )
					break;
				room->startGame();
				break;
			}
		case PlayerStateLoadingGame:
			{
				printf("receive loading game packet\n");
				unsigned int playerId;
				memcpy( &playerId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Player * player = server->getPlayer( playerId );
				if( !player || ( player && player->getPlayerState() != PlayerStateLoadingGame ) )
					break;
				unsigned int lprog;
				memcpy( &lprog, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				player->setLoadingProgress( lprog );
				break;
			}
		case PlayerStateLoadingGameComplete:
			{
				printf("receive loading complete packet\n");
				unsigned int playerId;
				memcpy( &playerId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Player * player = server->getPlayer( playerId );
				if( !player || ( player && player->getPlayerState() != PlayerStateLoadingGame ) )
					break;
				player->setPlayerState( PlayerStateLoadingGameComplete );
				break;
			}
		case PlayerStateInGame:
			{
				printf("receive in game packet\n");
				unsigned int playerId;
				memcpy( &playerId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				unsigned int roomId;
				memcpy( &roomId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				unsigned int forceId;
				memcpy( &forceId, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				PlayerAttribute playerAttr;
				memcpy( &playerAttr.timeStamp, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				memcpy( &playerAttr.posX, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				memcpy( &playerAttr.posY, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				memcpy( &playerAttr.velX, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				memcpy( &playerAttr.velY, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				memcpy( &playerAttr.itemInUse, &data[pos], sizeof( unsigned int ) );
				pos += sizeof( unsigned int );
				Player * player = server->getPlayer( playerId );
				if( player )
					player->updateGamePlayStates( playerAttr );
				break;
			}
		default:
			break;
		}
	}
}

int PacketHandler::wrapPlayerPacket( Player * player, unsigned char * data, int size )
{
	int s = 0;
	if( player )
	{
		PlayerState playerState = player->getPlayerState();
		//memcpy( &data[s], &playerState, sizeof( PlayerState ) );
		//s += sizeof( PlayerState );	
		switch( playerState )
		{
		case PlayerStateLoadingGame:
		case PlayerStateLoadingGameComplete:
			{
				unsigned int playerId = player->getPlayerId();
				memcpy( data + s, &playerId, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				float posX = player->getPosX();
				memcpy( data + s, &posX, sizeof( float ) );
				s += sizeof( float );
				float posY = player->getPosY();
				memcpy( data + s, &posY, sizeof( float ) );
				s += sizeof( float );
				unsigned int appearance = player->getAppearance();
				memcpy( data + s, &appearance, sizeof( float ) );
				s += sizeof( unsigned int );	
				unsigned int lprog = player->getLoadingProgress();
				memcpy( data + s, &lprog, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				break;
			}
		case PlayerStateInGame:
			{
				unsigned int playerId = player->getPlayerId();
				memcpy( &data[s], &playerId, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				bool isCorrection = player->getCorrection();
				memcpy( &data[s], &isCorrection, sizeof( bool ) );
				s += sizeof( bool );
				player->setCorrection( false );
				unsigned int timestamp = player->getTimeStamp();
				memcpy( &data[s], &timestamp, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				float posX = player->getPosX();
				memcpy( &data[s], &posX, sizeof( float ) );
				s += sizeof( float );
				float posY = player->getPosY();
				memcpy( &data[s], &posY, sizeof( float ) );
				s += sizeof( float );
				float velX = player->getVelX();
				memcpy( &data[s], &velX, sizeof( float ) );
				s += sizeof( float );
				float velY = player->getVelY();
				memcpy( &data[s], &velY, sizeof( float ) );
				s += sizeof( float );
				unsigned int itemOne = player->getItemOne();
				memcpy( &data[s], &itemOne, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				unsigned int itemTwo = player->getItemTwo();
				memcpy( &data[s], &itemTwo, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				unsigned int appearance = player->getAppearance();
				memcpy( &data[s], &appearance, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				break;
			}
		case PlayerStateGameEnd:
			{
				unsigned int playerId = player->getPlayerId();
				memcpy( &data[s], &playerId, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				unsigned int score = player->getScore();
				memcpy( &data[s], &score, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				GameResult gameResult = player->getGameResult();
				memcpy( &data[s], &gameResult, sizeof( unsigned int ) );
				s += sizeof( GameResult );
				break;
			}
		default:
			s = 0;
			break;
		}
	}

	return s;
}

int	PacketHandler::wrapRoomPacket( Room * room, unsigned char data[], int size )
{
	int s = 0;
	if( room )
	{
		RoomState roomState = room->getRoomState();
		switch( roomState )
		{
		case RoomStateWaiting:
			{
				PlayerState playerState = PlayerStateInRoom;
				memcpy( &data[s], &playerState, sizeof( PlayerState ) );
				s += sizeof( PlayerState );
				unsigned int roomId = room->getRoomId();
				memcpy( &data[s], &roomId, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				unsigned char roomCapacity = room->getMaxPlayerNumber();
				memcpy( &data[s], &roomCapacity, sizeof( unsigned char ) );
				s += sizeof( unsigned char );
				unsigned char numForces = room->getNumForces();
				memcpy( &data[s], &numForces, sizeof( unsigned char ) );
				s += sizeof( unsigned char );
				unsigned int mapId = room->getMapId();
				memcpy( &data[s], &mapId, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				unsigned int hostId = room->getHostId();
				memcpy( &data[s], &hostId, sizeof( unsigned int ) );
				s += sizeof( unsigned int );
				std::list<Player *> playerList = room->getPlayerList();
				unsigned char numPlayer = ( unsigned char )playerList.size();
				memcpy( &data[s], &numPlayer, sizeof( unsigned char ) );
				s += sizeof( unsigned char );
				for( std::list<Player*>::iterator itr = playerList.begin(); itr != playerList.end(); ++itr )
				{
					Player * player = ( *itr );
					unsigned int playerId = player->getPlayerId();	
					memcpy( &data[s], &playerId, sizeof( unsigned int ) );
					s += sizeof( unsigned int );
					unsigned int playerNameSize;
					char playerName[kMaxPlayerNameLength];
					player->getPlayerName( &playerName[0], &playerNameSize );
					memcpy( &data[s], &playerNameSize, sizeof( unsigned int ) );
					s += sizeof( unsigned int );
					memcpy( &data[s], &playerName[0], playerNameSize );
					s += playerNameSize;
					unsigned char playerForce = player->getForceId();
					memcpy( &data[s], &playerForce, sizeof( unsigned char ) );
					s += sizeof( unsigned char );
					PlayerState playerState = player->getPlayerState();
					memcpy( &data[s], &playerState, sizeof( PlayerState ) );
					s += sizeof( PlayerState );
				}
				break;
			}
		case RoomStateLoadingGame:
		case RoomStateInGame:
			{
				if( roomState == RoomStateLoadingGame )
				{
					PlayerState playerState = PlayerStateLoadingGame;
					memcpy( &data[s], &playerState, sizeof( PlayerState ) );
					s += sizeof( PlayerState );
				}
				else if( roomState == RoomStateInGame )
				{
					PlayerState playerState = PlayerStateInGame;
					memcpy( &data[s], &playerState, sizeof( PlayerState ) );
					s += sizeof( PlayerState );	
					RoleType roleType = RolePlayer;
					memcpy( &data[s], &roleType, sizeof( roleType ) );
					s += sizeof( roleType );
				}
				else if( roomState == RoomStateGameEnd )
				{
					PlayerState playerState = PlayerStateGameEnd;
					memcpy( &data[s], &playerState, sizeof( PlayerState ) );
					s += sizeof( PlayerState );
				}
				unsigned int numPlayers = room->getCurrentPlayerNumber();
				memcpy( &data[s], &numPlayers, sizeof( numPlayers ) );
				s += sizeof( unsigned int );
				std::list<Player *> playerList = room->getPlayerList();
				for( std::list<Player *>::iterator itr = playerList.begin(); itr != playerList.end(); ++itr )
				{
					Player * player = ( *itr );
					if( player )
					{
						unsigned int wrapBytes = wrapPlayerPacket( player, &data[s], 256 - s );
						s += wrapBytes;
					}
				}
				break;
			}
		default:
			return 0;
		}
	}

	return s;
}

int	PacketHandler::wrapRoomListPacket( Server * server, Player* player, unsigned char data[], int size )
{
	int s = 0;
	if( server && player )
	{
		PlayerState playerState = player->getPlayerState();
		memcpy( &data[s], &playerState, sizeof( PlayerState ) );
		s += sizeof( PlayerState );	
		unsigned int playerId = player->getPlayerId();
		memcpy( &data[s], &playerId, sizeof( unsigned int ) );
		s += sizeof( unsigned int );	
		std::list<Room *> roomList = server->getRoomList();
		unsigned int roomNum = roomList.size();
		memcpy( &data[s], &roomNum, sizeof( unsigned int ) );
		s += sizeof( unsigned int );
		for( std::list<Room *>::iterator itr = roomList.begin(); itr != roomList.end(); ++itr )
		{
			Room * room = ( *itr );
			unsigned int roomId = room->getRoomId();
			memcpy( &data[s], &roomId, sizeof( unsigned int ) );
			s += sizeof( unsigned int );
			unsigned char roomCap = room->getMaxPlayerNumber();
			memcpy( &data[s], &roomCap, sizeof( unsigned char ) );
			s += sizeof( unsigned char );
			unsigned char currentNum = room->getCurrentPlayerNumber();
			memcpy( &data[s], &currentNum, sizeof( unsigned char ) );
			s += sizeof( unsigned char );
			unsigned char numForces = room->getNumForces();
			memcpy( &data[s], &numForces, sizeof( unsigned char ) );
			s += sizeof( unsigned char );
			unsigned int mapId = room->getMapId();
			memcpy( &data[s], &mapId, sizeof( unsigned int ) );
			s += sizeof( unsigned int );
		}
	}

	return s;
}